#!/usr/bin/env python3
import sys
from PyQt5.QtCore import *
#from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import ( QAction, QApplication,  QMessageBox, QTextEdit, QMenu, QFileDialog)
from PyQt5.QtGui import  QCursor, QFont, QColor, QPixmap, QTextCursor, QPalette
from PyQt5.QtPrintSupport import *

from PyQt5.Qsci import QsciLexerCPP, QsciScintilla, QsciAPIs,QsciScintillaBase 
#from PyQt5.Qsci import QsciDocument
from qrc_resources  import   *
from lexer_c_getfunc import g_allFuncList
import keyword
class MyLexerCPP(QsciLexerCPP):
    def __init__(self,parent):
        QsciLexerCPP.__init__(self,parent)
        if parent == None:
            return
        self.setFont(self.parent().Font)
        #颜色由主界面传入，存于《setting.ini》中
        self.setColor(QColor(self.parent().win.colorDict[ 'Default'  ]))    #设置前景色
        self.setPaper(QColor(self.parent().win.colorDict[ 'Background'  ]))    #设置底色
        
        self.setColor(QColor(self.parent().win.colorDict['Default'   ]), QsciLexerCPP.Default       ) 
        self.setColor(QColor(self.parent().win.colorDict['Keyword'                    ]), QsciLexerCPP.Keyword       )  
        self.setColor(QColor(self.parent().win.colorDict['KeywordSet2'              ]), QsciLexerCPP.KeywordSet2       )           
        self.setColor(QColor(self.parent().win.colorDict['CommentDoc'               ]), QsciLexerCPP.CommentDoc    )#文档注释 /**开头的颜色
        self.setColor(QColor(self.parent().win.colorDict['Comment'                    ]), QsciLexerCPP.Comment       )#块注释 的颜色
        self.setColor(QColor(self.parent().win.colorDict['CommentLine'              ]), QsciLexerCPP.CommentLine   )#行注释的颜色
        self.setColor(QColor(self.parent().win.colorDict['Number'                      ]), QsciLexerCPP.Number            )       #数字 的颜色
        self.setColor(QColor(self.parent().win.colorDict['DoubleQuotedString'   ]), QsciLexerCPP.DoubleQuotedString)#双引号字符串的颜色
        self.setColor(QColor(self.parent().win.colorDict['SingleQuotedString'   ]), QsciLexerCPP.SingleQuotedString)#单引号字符的颜色
        self.setColor(QColor(self.parent().win.colorDict['PreProcessor'            ]), QsciLexerCPP.PreProcessor      )#预编译语句的颜色
        self.setColor(QColor(self.parent().win.colorDict['Operator'                   ]), QsciLexerCPP.Operator          )
        self.setColor(QColor(self.parent().win.colorDict['UnclosedString'         ]), QsciLexerCPP.UnclosedString)#未完成输入的字符串的颜色
        #self.setColor(QColor("#000000"), QsciLexerCPP.Identifier)  #可识别字符的颜色，这个范围很广，包含了关键词，函数名；所以要取消这句
        
        font = QFont(self.parent().Font)
        font.setBold(True)
        self.setFont(font,5)    #默认的字体加粗。
        
        font = QFont(self.parent().Font)
        font.setItalic(True)        
        self.setFont(font,QsciLexerCPP.Comment)   #注释的字体用斜体。
        
        for i in range(0, QsciScintillaBase.STYLE_MAX):
            desc = self.description(i)
            if desc: 
                self.setEolFill(True, i)    #将填充的底色延伸到屏幕的右端；否则默认只有文字的地方。

class SciTextEdit(QsciScintilla):
    NextId = 1

    def __init__(self, filename='', wins=None, parent=None):
        global g_allFuncList
        super(QsciScintilla, self).__init__(parent)
        self.win=wins
        self.jumpName=''
        self.list_line=[]
        self.Font = self.win.EditFont   #采用主窗口传入的字体
        self.Font.setFixedPitch(True)
        self.setFont(self.Font)
        
        #1.设置文档的编码格式为 “utf8” ，换行符为 windows   【可选linux，Mac】
        self.setUtf8(True)        
        self.setEolMode(QsciScintilla.SC_EOL_CRLF)#文件中的每一行都以EOL字符结尾（换行符为 \r \n）
        #2.设置括号匹配模式
        self.setBraceMatching(QsciScintilla.StrictBraceMatch)# 
        #3.设置 Tab 键功能
        self.setIndentationsUseTabs(True)#行首缩进采用Tab键，反向缩进是Shift +Tab
        self.setIndentationWidth(4)     #行首缩进宽度为4个空格
        self.setIndentationGuides(True)#    显示虚线垂直线的方式来指示缩进
        self.setTabIndents(True)    #编辑器将行首第一个非空格字符推送到下一个缩进级别
        self.setAutoIndent(True)    #插入新行时，自动缩进将光标推送到与前一个相同的缩进级别
        self.setBackspaceUnindents(True)
        self.setTabWidth(4)         # Tab 等于 4 个空格
        #4.设置光标
        self.setCaretWidth(2)           #光标宽度（以像素为单位），0表示不显示光标
        self.setCaretForegroundColor(QColor("darkCyan"))    #光标颜色
        self.setCaretLineVisible(True)      #是否高亮显示光标所在行
        self.setCaretLineBackgroundColor(QColor(self.win.colorDict[ 'CaretLine'  ]))     #光标所在行的底色
        #5.设置页边特性。        这里有3种Margin：[0]行号    [1]改动标识   [2]代码折叠
            #5.1 设置行号
        self.setMarginsFont(self.Font)      #行号字体
        self.setMarginLineNumbers(0,True)    #设置标号为0的页边显示行号    
        self.setMarginWidth(0,'00000')  #行号宽度
        self.setMarkerForegroundColor(QColor("#FFFFFF"),0)  
        self.setMarginsBackgroundColor(QColor(self.win.colorDict[ 'Background'  ]))
        #self.setMarkerBackgroundColor(QColor(self.win.colorDict[ 'Background'  ]),0)
        #self.setMarkerBackgroundColor(QColor(self.win.colorDict[ 'Background'  ]),1)
        #self.setMarkerBackgroundColor(QColor(self.win.colorDict[ 'Background'  ]),2)  
        
            #5.2 设置改动标记    
        self.setMarginType(1, QsciScintilla.SymbolMargin)   # 设置标号为1的页边用于显示改动标记 
        self.setMarginWidth(1, "0000")          #改动标记占用的宽度
        #img = QPixmap(":/leftside.png")     #改动标记图标，大小是48 x 48
        #sym_1 = img.scaled(QSize(16, 16))       #图标缩小为 16 x 16 #         
        sym_1 = QsciScintilla.LeftRectangle
        
        self.markerDefine(sym_1, 0)     
        self.setMarginMarkerMask(1, 0b1111)
        self.setMarkerForegroundColor(QColor("#ff0000"),0)  
        self.setMarkerBackgroundColor(QColor("#00ff00"),0)  #00ff00    
            #5.3  设置代码自动折叠区域
        self.setFolding(QsciScintilla.PlainFoldStyle)
        self.setMarginWidth(2,12)
                #5.3.1 设置代码折叠和展开时的页边标记 - +
        self.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPEN)
        self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDER)
        self.markerDefine(QsciScintilla.Minus, QsciScintilla.SC_MARKNUM_FOLDEROPENMID)
        self.markerDefine(QsciScintilla.Plus, QsciScintilla.SC_MARKNUM_FOLDEREND)
                #5.3.2 设置代码折叠后，+ 的颜色FFFFFF
        self.setMarkerBackgroundColor(QColor("#FFBCBC"), QsciScintilla.SC_MARKNUM_FOLDEREND)
        self.setMarkerForegroundColor(QColor("red"), QsciScintilla.SC_MARKNUM_FOLDEREND)
    
        #6.语法高亮显示
            #6.1语法高亮的设置见 MyLexerCPP类 源码
        self.lexer=MyLexerCPP(self)
        self.setLexer(self.lexer)
            #6.2设置自动补全
        self.mod=False
        self.__api = QsciAPIs(self.lexer)
            # SDCC编译器的关键字 列表
        sdcc_kwlist=['__data','__idata','__pdata','__xdata','__code','__bit','__sbit',
                        '__sfr' , 'u8', 'u16' , 'WORD', 'BYTE','define' , 'include','__interrupt',  
                        '__critical', '__using','double' , 'int' , 'struct' , 'break' , 'else' ,  
                        'auto' ,'switch' , 'case','enum' , 'register' , 'typedef' , 'default' , 
                        'char' , 'extern' , 'return' , 'union' , 'const' , 'float','long' ,
                       'short' , 'unsigned' , 'continue' , 'for' , 'signed' , 'void' , 
                       'goto','sizeof' , 'volatile' , 'do' , 'while' , 'static' , 'if', 
                       'endif', 'ifndef', 'ifdef','import']
        pykwlist="ACCEL_X|ACCEL_Y|ACCEL_Z|ADC|ADCWiPy|AF_INET|AF_INET6|ALTITUDE|ARRAY|AbstractBlockDev|AbstractNIC|BIG_ENDIAN|BLE|BytesIO|CAN.BUS_OFF|CAN.ERROR_ACTIVE|CAN.ERROR_PASSIVE|CAN.ERROR_WARNING|CAN.LIST16|CAN.LIST32|CAN.LOOPBACK|CAN.MASK16|CAN.MASK32|CAN.NORMAL|CAN.SILENT|CAN.SILENT_LOOPBACK|CAN.STOPPED|CC3K|CC3K.WEP|CC3K.WPA|CC3K.WPA2|CPython|CircuitPython|Collector|DEBUG|DESC|DIE_TEMP|DecompIO|DiskAccess|Event|Exception|ExtInt.IRQ_FALLING|ExtInt.IRQ_RISING|ExtInt.IRQ_RISING_FALLING|FFI|FLOAT32|FLOAT64|FileIO|Flash|FlashArea|FrameBuffer|GPIO|GYRO_X|GYRO_Y|GYRO_Z|Garbage|HEAP_DATA|HEAP_EXEC|HUMIDITY|I2C|I2C.CONTROLLER|I2C.PERIPHERAL|I2S|I2S.MONO|I2S.RX|I2S.STEREO|I2S.TX|INCL|INT16|INT32|INT64|INT8|IPPROTO_SEC|IPPROTO_TCP|IPPROTO_UDP|KeyboardInterrupt|LCD160CR|LCD160CR.h|LCD160CR.w|LIGHT|LITTLE_ENDIAN|Lock|Loop|MAGN_X|MAGN_Y|MAGN_Z|MCU|MICROPYINSPECT|MICROPYPATH|MicroPython|NATIVE|NVS|NeoPixel|PIO|PIO.IN_HIGH|PIO.IN_LOW|PIO.IRQ_SM0|PIO.IRQ_SM1|PIO.IRQ_SM2|PIO.IRQ_SM3|PIO.JOIN_NONE|PIO.JOIN_RX|PIO.JOIN_TX|PIO.OUT_HIGH|PIO.OUT_LOW|PIO.SHIFT_LEFT|PIO.SHIFT_RIGHT|PRESS|PROX|PTR|PWM|Partition|Partition.BOOT|Partition.RUNNING|Partition.TYPE_APP|Partition.TYPE_DATA|Pin|Pin.AF_OD|Pin.AF_PP|Pin.ALT|Pin.ALT_OPEN_DRAIN|Pin.ANALOG|Pin.HIGH_POWER|Pin.IN|Pin.IRQ_FALLING|Pin.IRQ_HIGH_LEVEL|Pin.IRQ_LOW_LEVEL|Pin.IRQ_RISING|Pin.LOW_POWER|Pin.MED_POWER|Pin.OPEN_DRAIN|Pin.OUT|Pin.OUT_OD|Pin.OUT_PP|Pin.PULL_DOWN|Pin.PULL_HOLD|Pin.PULL_NONE|Pin.PULL_UP|REPL|RMT|RTC|RTC.ALARM0|SD|SDCard|SOCK_DGRAM|SOCK_STREAM|SPI|SPI.CONTROLLER|SPI.LSB|SPI.MSB|SPI.PERIPHERAL|Sensor|Server|Signal|SoftI2C|SoftSPI|State|Machine|StopIteration|Stream|StringIO|SystemExit|Task|TextIOWrapper|ThreadSafeFlag|Timer|Timer.A|Timer.B|Timer.MATCH|Timer.NEGATIVE|Timer.ONE_SHOT|Timer.PERIODIC|Timer.POSITIVE|Timer.PWM|Timer.TIMEOUT|TimerWiPy|TimerWiPy.ONE_SHOT|TimerWiPy.PERIODIC|UART|UART.CTS|UART.RTS|UART.RX_ANY|UINT16|UINT32|UINT64|UINT8|ULP|USB_VCP.CTS|USB_VCP.IRQ_RX|USB_VCP.RTS|UUID|Unix|VOID|VfsFat|VfsLfs1|VfsLfs2|WDT|WIZNET5K|WLAN|WLANWiPy|WLANWiPy.AP|WLANWiPy.EXT_ANT|WLANWiPy.INT_ANT|WLANWiPy.STA|WLANWiPy.WEP|WLANWiPy.WPA|WLANWiPy.WPA2|__call__()|__contains__()|__delitem__()|__getitem__()|__init__()|__iter__()|__len__()|__setitem__()|__str__()|_thread|a2b_base64()|abs()|abstract|accept()|acos()|acosh()|acquire()|active()|adcchannel()|add_program()|addressof()|aes|af()|af_list()|aiter()|alarm()|alarm_left()|all()|alloc_emergency_exception_buf()|alt_list()|anext()|angle()|antenna()|any()|append()|argv|array|as|ascii()|asin()|asinh()|asm_pio()|asm_pio_encode()|atan()|atan2()|atanh()|atexit()|atten()|auth()|b2a_base64()|baremetal|base|bin()|binascii|bind()|bitstream()|blit()|bluetooth|board|bool|bool()|bootloader()|break|breakpoint()|btree|buffer|built-in|bytearray|bytearray()|bytearray_at()|bytecode|byteorder|bytes|bytes()|bytes_at()|calcsize()|calibration()|call_exception_handler()|callable()|callback()|callee-owned|cancel()|capture()|case|catch|ceil()|channel()|chdir()|checked|chr()|classmethod()|clear()|clearfilter()|clock_div()|close()|cmath|collect()|collections|command|command()|commit()|compare()|compile()|complex|complex()|config()|connect()|const()|continue|contrast()|copysign()|cos()|cosh()|counter()|create_task()|cross-compiler|cryptolib|current_task()|current_tid()|DAC|machine.DAC||datetime()|debug()|decompress()|decrypt()|deepsleep()|default|default_exception_handler()|degrees()|deinit()|delattr()|delay()|delegate|deque()|dict|dict()|digest()|dir()|disable()|disable_irq()|disconnect()|divmod()|do|dot()|dot_no_clip()|drain()|drive()|driver|dump()|dumps()|dupterm()|duty_cycle()|duty_ns()|duty_u16()|elapsed_micros()|elapsed_millis()|else|enable()|enable_irq()|encrypt()|end()|enumerate()|environment|erase()|erase_key()|erf()|erfc()|errno|error|code|esp|esp32|esp32.WAKEUP_ALL_LOW|esp32.WAKEUP_ANY_HIGH|eval()|event|exec()|exit()|exp()|explicit|expm1()|extend()|extern|fabs()|false|fast_spi()|fault_debug()|feed()|feed_wdt()|filesystem|fill()|fill_rect()|filter()|filtered_xyz()|finally|find()|fixed|flash_erase()|flash_id()|flash_read()|flash_size()|flash_user_start()|flash_write()|float|float()|floor()|flush()|fmod()|for|foreach|format()|framebuf|framebuf.GS2_HMSB|framebuf.GS4_HMSB|framebuf.GS8|framebuf.MONO_HLSB|framebuf.MONO_HMSB|framebuf.MONO_VLSB|framebuf.RGB565|freq()|frexp()|from|from_bytes()|frozen|frozenset|frozenset()|function|gamma()|gap_advertise()|gap_connect()|gap_disconnect()|gap_pair()|gap_passkey()|gap_scan()|gather()|gattc_discover_characteristics()|gattc_discover_descriptors()|gattc_discover_services()|gattc_exchange_mtu()|gattc_read()|gattc_write()|gatts_indicate()|gatts_notify()|gatts_read()|gatts_register_services()|gatts_set_buffer()|gatts_write()|gc|get()|get_blob()|get_event_loop()|get_exception_handler()|get_extra_info()|get_float()|get_i32()|get_int()|get_line()|get_micros()|get_millis()|get_next_update()|get_pixel()|get_touch()|getaddrinfo()|getattr()|getcwd()|getvalue()|globals()|gmtime()|goto|gpio()|group()|groups()|hall_sensor()|hard_reset()|hasattr()|hash()|hashlib|hashlib.md5|hashlib.sha1|hashlib.sha256|have_cdc()|heap|heap_lock()|heap_locked()|heap_unlock()|heapify()|heappop()|heappush()|heapq|heartbeat()|help()|hex()|hexdigest()|hexlify()|hid()|high()|hline()|id()|idf_heap_info()|idle()|if|ifconfig()|ilistdir()|implementation|implicit|import|in|index()|inet_ntop()|inet_pton()|info()|init()|initfilterbanks()|input()|int|int()|intensity()|interface|internal|interned|io|ioctl()|ipoll()|irq()|is|is_preempt_thread()|is_ready()|is_set()|is_touched()|isconnected()|isfinite()|isinf()|isinstance()|isnan()|isrunning()|issubclass()|items()|iter()|jpeg()|jpeg_data()|jpeg_start()|json|kbd_intr()|keys()|l2cap_connect()|l2cap_disconnect()|l2cap_listen()|l2cap_recvinto()|l2cap_send()|lcd160cr|lcd160cr.LANDSCAPE|lcd160cr.LANDSCAPE_UPSIDEDOWN|lcd160cr.PORTRAIT|lcd160cr.PORTRAIT_UPSIDEDOWN|lcd160cr.STARTUP_DECO_INFO|lcd160cr.STARTUP_DECO_MLOGO|lcd160cr.STARTUP_DECO_NONE|ldexp()|len()|lgamma()|light()|lightsleep()|line|line()|line_no_clip()|list|list()|listdir()|listen()|load()|load_binary()|loads()|locals()|localtime()|lock|locked()|log()|log10()|log2()|loop()|low()|mac()|machine|machine.DEEPSLEEP|machine.DEEPSLEEP_RESET|machine.HARD_RESET|machine.IDLE|machine.PIN_WAKE|machine.PWRON_RESET|machine.RTC_WAKE|machine.SLEEP|machine.SOFT_RESET|machine.WDT_RESET|machine.WLAN_WAKE|main()|makefile()|map()|mapper()|mark_app_valid_cancel_rollback()|match()|math|max()|maxsize|measure()|mem_alloc()|mem_free()|mem_info()|mem_read()|mem_write()|memoryview|memoryview()|micropython|micropython-lib|micros()|millis()|min()|mkdir()|mkfs()|mktime()|mode()|modf()|modify()|mount()|name()|namedtuple()|names()|namespace|native|neopixel|network|network.Server|new|new_event_loop()|next()|noise()|now()|null|object|object()|oct()|off()|on()|open()|open_connection()|operator|opt_level()|option|ord()|os|out|override|pack()|pack_into()|params|patch_program()|patch_version()|path|period()|phase()|phy_mode()|pi|pin()|pixel()|platform|polar()|poll()|poly_dot()|poly_line()|popleft()|port|port()|pow()|prescaler()|print()|print_exception()|private|property()|protected|protocol|public|pull()|pulse_width()|pulse_width_percent()|put()|pyb|pyb.ADC|pyb.Accel|pyb.CAN|pyb.DAC|pyb.ExtInt|pyb.Flash|pyb.I2C|pyb.LCD|pyb.LED|pyb.Pin|pyb.RTC|pyb.SPI|pyb.Servo|pyb.Switch|pyb.Timer|pyb.UART|pyb.USB_HID|pyb.USB_VCP|qstr_info()|radians()|range()|raw_temperature()|re|read()|read_timed()|read_timed_multi()|read_u16()|readblocks()|readchar()|readexactly()|readfrom()|readfrom_into()|readfrom_mem()|readfrom_mem_into()|readinto()|readline()|readlines()|readonly|rect()|rect_interior()|rect_interior_no_clip()|rect_no_clip()|rect_outline()|rect_outline_no_clip()|recv()|recvfrom()|ref|reg()|register()|regs()|release()|remove()|remove_program()|rename()|repl_uart()|repr()|reset()|reset_cause()|restart()|return|reversed()|rgb()|rmdir()|rng()|round()|rp2|run()|run_forever()|run_until_complete()|rx_fifo()|rxcallback()|save_to_flash()|scan()|schedule()|screen_dump()|screen_load()|scroll()|sealed|search()|select|select()|send()|send_recv()|sendall()|sendbreak()|sendto()|set|set()|set_blob()|set_boot()|set_brightness()|set_exception_handler()|set_font()|set_i2c_addr()|set_i32()|set_native_code_location()|set_orient()|set_pen()|set_pixel()|set_pos()|set_power()|set_scroll()|set_scroll_buf()|set_scroll_win()|set_scroll_win_param()|set_spi_win()|set_startup_deco()|set_text_color()|set_uart_baudrate()|set_wakeup_period()|setattr()|setblocking()|setfilter()|setinterrupt()|setsockopt()|settimeout()|shell_exec()|shift()|show()|show_framebuf()|sin()|sinh()|sizeof|sizeof()|sleep()|sleep_ms()|sleep_type()|sleep_us()|slice|slice()|slicea()|socket|socket()|socket.error|soft_reset()|sorted()|source_freq()|span()|speed()|split()|sqrt()|ssid()|ssl|ssl.CERT_NONE|ssl.CERT_OPTIONAL|ssl.CERT_REQUIRED|ssl.SSLError|ssl.wrap_socket()|stack_use()|stackalloc|standby()|start()|start_server()|stat()|state()|state_machine()|staticmethod()|status()|statvfs()|stderr|stdin|stdout|stop()|str|str()|stream|string|struct|sub()|sum()|super()|swint()|switch|sync()|sys|tan()|tanh()|text()|this|thread_analyze()|threshold()|throw|ticks_add()|ticks_cpu()|ticks_diff()|ticks_ms()|ticks_us()|tilt()|time|time()|time_ns()|time_pulse_us()|timeout()|to_bytes()|toggle()|touch_config()|triangle()|true|trunc()|try|tuple|tuple()|tx_fifo()|type()|typeof|uarray|uasyncio|ubinascii|ubluetooth|ucollections|ucryptolib|uctypes|udelay()|uerrno|uhashlib|uheapq|uio|ujson|umount()|uname()|unchecked|unhexlify()|unique_id()|unmount()|unpack()|unpack_from()|unregister()|unsafe|uos|update()|upip|urandom()|ure|usb_mode()|uselect|using|usocket|ussl|ustruct|usys|utime|uzlib|value()|values()|variable|vars()|version|version_info|virtual|vline()|wait()|wait_closed()|wait_done()|wait_for()|wait_for_ms()|wake_on_ext0()|wake_on_ext1()|wake_on_touch()|wake_reason()|wakeup()|wfi()|while|width()|wipy|write()|write_pulses()|write_readinto()|write_timed()|writeblocks()|writechar()|writeto()|writeto_mem()|writevto()|zephyr|zip()|zlib|zsensor".split('|')
        autocompletions = keyword.kwlist+sdcc_kwlist+pykwlist
        for ac in autocompletions:
            self.__api.add(ac)
        self.__api.prepare()
        self.autoCompleteFromAll()
        self.setAutoCompletionSource(QsciScintilla.AcsAll) #自动补全所以地方出现的
        self.setAutoCompletionCaseSensitivity(True) #设置自动补全大小写敏感
        self.setAutoCompletionThreshold(1);     #输入1个字符，就出现自动补全 提示
        self.setAutoCompletionReplaceWord(False)
        self.setAutoCompletionUseSingle(QsciScintilla.AcusExplicit)
        self.setAttribute(Qt.WA_DeleteOnClose)
        #设置函数名为关键字2    KeyWord = sdcc_kwlistcc  ;KeywordSet2 = 函数名
        self.SendScintilla(QsciScintilla.SCI_SETKEYWORDS, 0," ".join(sdcc_kwlist).encode(encoding='utf-8'))
        #self.SendScintilla(QsciScintilla.SCI_STYLESETFORE, QsciLexerCPP.KeywordSet2, 0x7f0000)
        self.SendScintilla(QsciScintilla.SCI_SETKEYWORDS, 1," ".join(g_allFuncList).encode(encoding='utf-8'))
        
        
        self.filename = filename
        if self.filename=='':
            self.filename = str("未命名-{0}".format(SciTextEdit.NextId))
            SciTextEdit.NextId += 1
        self.setModified(False)
        #设置文档窗口的标题
        self.setWindowTitle(QFileInfo(self.filename).fileName())
        #将槽函数链接到文本改动的信号
        self.textChanged.connect(self.textChangedAction)
        #给文档窗口添加右键菜单
        self.setContextMenuPolicy(Qt.CustomContextMenu)#
        self.customContextMenuRequested.connect(self.RightMenu)
       
    def getIncludeFile(self, linestr):
        start=0
        end=0
        for i in range(7, len(linestr)):
            if start !=0 and linestr[i] in ' >"':
                end = i+1
                return linestr[start: end]
            elif start ==0 and linestr[i] in '<"':
                start = i
        return None 
    
    def getFuncNameInLine(self, linestr):     #在行中查找函数名  
        start=0
        end=linestr.find('(')
        if end == 0:
            return None
        for i in range(end-1, -1, -1):  #从 左括号字符 “(” 往回查询到空格、= 、制表符 就停止
            if start !=0 and  linestr[i] in " =\t":
                end = start
                start = i+1
                break
            # 左括号 和 函数名 之间有可能包含空格
            elif start ==0 and linestr[i] != ' ' :  #非空格，就是函数名最后一个字符，把位置保存在start
                start = i+1
        else:
            end=0
        return linestr[start: end]

    def RightMenu(self):
        line_num, index=self.getCursorPosition()
        text=self.text()
        #0.获取光标所在行的全部字符
        str1=text.splitlines(False)[line_num]
        if len(str1) != 0:
            #0.1 如果字符串有 ‘#in’ ，那么应该包含文件名
            if '#in' in str1:     
                self.jumpName = self.getIncludeFile(str1)
            #0.2 如果含有 字符 (  ,那么应该有函数名
            elif '(' in str1:  
                self.jumpName= self.getFuncNameInLine(str1)
        #1.Jump to
        self.popMenu = QMenu()
        Jump2Function=QAction('跳转到 '+self.jumpName, self)
        self.popMenu.addAction(Jump2Function)
        Jump2Function.triggered.connect(self.do_Jump2Function)
        #setEnabled   isRedoAvailable  isUndoAvailable
        #2.undo    
        undoAction =QAction('撤销', self)
        undoAction.triggered.connect(self.undo)
        undoAction.setEnabled(self.isUndoAvailable())
        self.popMenu.addAction(undoAction)
        #3.redo 
        redoAction =QAction('重做', self)
        redoAction.triggered.connect(self.redo)
        redoAction.setEnabled(self.isRedoAvailable())
        self.popMenu.addAction(redoAction)
        #4.copy      
        copyAction =QAction('复制', self)
        copyAction.triggered.connect(self.copy)
        self.popMenu.addAction(copyAction)
        #5.cut 
        cutAction =QAction('剪切', self)
        cutAction.triggered.connect(self.cut)
        self.popMenu.addAction(cutAction)
        #6.paste
        pasteAction =QAction('粘贴', self)
        pasteAction.triggered.connect(self.paste)
        self.popMenu.addAction(pasteAction)
         #7.在鼠标位置显示右菜单    
        self.popMenu.exec_(QCursor.pos())
    def do_Jump2Function(self): # 跳转到函数 ；跳转到包含文件
        if self.jumpName[0] in '"<' :
            self.win.Jump2IncludeFile_Signal.emit(self.jumpName)
        else:
            self.win.Jump2Func_Signal.emit(self.jumpName)
    
    def closeEvent(self, event):
        if (self.isModified() and 
            QMessageBox.question(self,
                   "文本编辑器 - 未保存的更改",
                   "保存在 {0} 文件中所做出的更改?".format(self.filename),
                   QMessageBox.Yes|QMessageBox.No) ==
                QMessageBox.Yes):
            try:
                self.save()
            except EnvironmentError as e:
                QMessageBox.warning(self,
                        "文本编辑器 - 保存错误",
                        "保存失败 {0}: {1}".format(self.filename, e))

    def textChangedAction(self):
        line, index=self.getCursorPosition()    #获取当前光标所在行
        handle_01 = self.markerAdd(line, 0)     # 添加改动标记
        self.list_line.append(handle_01)        #保存改动标记所在的地方，给后面保存文档时消除标记提供信息
        
    def save(self):
        if self.filename[:3]=='未命名':
            if self.filename[-4:]==".txt":
                self.filename=self.filename[:-4]
            filename = QFileDialog.getSaveFileName(self, "文本编辑器 - 另存为", self.filename,
                    "c files (*.c *.*)")
            if filename[0]=='':
                return
            self.filename = filename[0]
        self.setWindowTitle(QFileInfo(self.filename).fileName())
        exception = None
        fh = None
        try:
            fh = QFile(self.filename)
            if not fh.open(QIODevice.WriteOnly):
                raise IOError(str(fh.errorString()))
            stream = QTextStream(fh)
            stream.setCodec("UTF-8")
            stream << self.text()
            #self.document().setModified(False)
            self.setModified(False)
        except EnvironmentError as e:
            exception = e
        finally:
            if fh is not None:
                fh.close()
            if exception is not None:
                raise exception
        #将保存过的文件消除改动标识,清空记录改动的列表
        for line in self.list_line:
            self.markerDeleteHandle(line)
        self.list_line.clear()

    def load(self):
        exception = None
        fh = None
        try:
            fh = QFile(self.filename)
            if not fh.open(QIODevice.ReadOnly):
                raise IOError(str(fh.errorString()))
            stream = QTextStream(fh)
            stream.setCodec("UTF-8")
            self.setText(stream.readAll())
            #self.document().setModified(False)
            self.setModified(False)
        except EnvironmentError as e:
            exception = e
        finally:
            if fh is not None:
                fh.close()
            if exception is not None:
                raise exception
'''
if __name__=="__main__":
    app=QApplication(sys.argv)
    form=TextEdit()
    form.show()
    app.exec_()
        
    def mousePressEvent(self, event):
        """Overloaded mouse click event"""
        #Execute the superclass mouse click event
        super().mousePressEvent(event)
        #Set focus to the clicked editor
        self.setFocus()
        # Hide the function wheel if it is shown
        key1=event.button()
        #模拟鼠标左键单击 QMouseEvent(QEvent::Type type, const QPointF &localPos, Qt::MouseButton button, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
        #event.button()=QtCore.Qt.LeftButton
        
        if key1 == QtCore.Qt.RightButton:
            print("right mouse")
     
    def keyPressEvent(self, QKeyEvent):#重写按键事件
        super().keyPressEvent(QKeyEvent)
        key = QKeyEvent.key()
        if key == Qt.Key_ParenLeft:
            #print("( press down")
            pos = self.SendScintilla(QsciScintilla.SCI_GETCURRENTPOS) #取得当前位置，注释掉的代码在包含中文代码中出错。
            start = self.SendScintilla(QsciScintilla.SCI_WORDSTARTPOSITION,  pos-2) # 纯英文下，运行正常
            end = self.SendScintilla(QsciScintilla.SCI_WORDENDPOSITION,  pos-2)
            self.SendScintilla(QsciScintilla.SCI_CALLTIPSHOW, pos, self.text()[start:end] )
            #self.CallTipShow(pos, self.text()[start:end] )
        elif key == Qt.Key_ParenRight:
            self.SendScintilla(QsciScintilla.SCI_CALLTIPCANCEL)
'''

class QtextEditClick(QTextEdit):
    TextEdit2Click_Signal = pyqtSignal()
    
    def __init__(self, parent=None):
        super(QtextEditClick, self).__init__(parent)        
        self.textChanged.connect(self.textChangedAction)#将槽函数链接到文本改动的信号
        
    def mouseDoubleClickEvent(self, e):
        self.TextEdit2Click_Signal.emit()   #产生一个文本双击信号
        
    def textChangedAction(self):
        cursor=self.textCursor()
        cursor.movePosition(QTextCursor.End)#移动鼠标至文档最后
        self.setTextCursor(cursor)
        QApplication.processEvents()
